package com.copa.gamestore.module.order.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.copa.gamestore.common.enums.PayStatus;
import com.copa.gamestore.module.cart.vo.CartVo;
import com.copa.gamestore.module.gameGoods.application.GameGoodsApplicationService;
import com.copa.gamestore.module.order.domain.Order;
import com.copa.gamestore.module.order.domain.OrderDetail;
import com.copa.gamestore.module.order.dto.OrderDto;
import com.copa.gamestore.module.order.mapper.OrderDetailMapper;
import com.copa.gamestore.module.order.mapper.OrderMapper;
import com.copa.gamestore.module.order.service.OrderLogService;
import com.copa.gamestore.module.order.service.OrderService;
import com.copa.gamestore.module.order.vo.OrderAdminListVo;
import com.copa.gamestore.module.order.vo.OrderLogVo;
import com.copa.gamestore.module.user.application.UserApplicationService;
import com.copa.gamestore.module.user.domain.UserAccount;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.validation.ValidationException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * @author copa
 * @createDate 2022-09-27 17:59
 * @function
 */
@Service
public class OrderServiceImpl implements OrderService {

    @Resource
    private OrderMapper orderMapper;

    @Resource
    private UserApplicationService userApplicationService;

    @Resource
    private OrderLogService orderLogService;

    @Resource
    private OrderDetailMapper orderDetailMapper;

    @Resource
    private GameGoodsApplicationService gameGoodsApplicationService;

    @Override
    public Order add(CartVo cartVo, OrderDto orderDto) {
        String orderSn = IdUtil.getSnowflake(1, 1).nextIdStr();
        Order order = new Order()
                .setUserId(userApplicationService.userInfo().getId())
                .setOrderSn(orderSn)
                .setAddress(orderDto.getAddress())
                .setStatus(PayStatus.WAITING.getStatus())
                .setPayUrl("http://localhost/order/pay?orderSn=" + orderSn + "&payStatus=" + PayStatus.PAY.getStatus())
                .setPayType(orderDto.getPayType())
                .setTotalPrice(cartVo.getMoney())
                .setActualPrice(new BigDecimal(0))
                .setRemark(orderDto.getRemark());
        if (orderMapper.insert(order) <= 0) {
            throw new RuntimeException();
        }
        return order;
    }

    @Override
    public BigDecimal finishPay(String orderSn) {
        synchronized (orderSn.intern()) {
            UserAccount account = userApplicationService.account().getData();
            Order order = Optional.ofNullable(orderMapper.selectOne(new QueryWrapper<Order>()
                    .eq("order_sn", orderSn)
                    .eq("user_id", account.getUserId())))
                    .orElseThrow(() -> new ValidationException("非法操作~"));
            if (PayStatus.WAITING.getStatus() != order.getStatus()) {
                throw new ValidationException("该订单不能被支付！");
            }
            if (account.getAccount().setScale(2).compareTo(order.getTotalPrice().setScale(2)) < 0) {
                throw new ValidationException("余额不足！");
            }
            order.setStatus(PayStatus.PAY.getStatus())
                    .setPayTime(LocalDateTime.now())
                    // 暂时没有搞优惠券什么的，所以还是原价
                    .setActualPrice(order.getTotalPrice());
            if (orderMapper.updateById(order) <= 0) {
                throw new RuntimeException();
            }
            return order.getActualPrice();
        }
    }

    @Override
    public void cancelPay(String orderSn) {
        synchronized (orderSn.intern()) {
            UserAccount account = userApplicationService.account().getData();
            Order order = Optional.ofNullable(orderMapper.selectOne(new QueryWrapper<Order>()
                            .eq("order_sn", orderSn)
                            .eq("user_id", account.getUserId())))
                    .orElseThrow(() -> new ValidationException("非法操作~"));
            if (PayStatus.WAITING.getStatus() != order.getStatus()) {
                throw new ValidationException("该订单不能被取消！");
            }
            order.setStatus(PayStatus.CANCEL.getStatus());
            if (orderMapper.updateById(order) <= 0) {
                throw new RuntimeException();
            }
        }
    }

    @Override
    public void receive(String orderSn) {
        UserAccount account = userApplicationService.account().getData();
        Order order = Optional.ofNullable(orderMapper.selectOne(new QueryWrapper<Order>().eq("order_sn", orderSn).eq("user_id", account.getUserId()))).orElseThrow(() -> new ValidationException("非法操作！"));
        if (PayStatus.PAY.getStatus() != order.getStatus()) {
            throw new ValidationException("该订单不能操作确认收货！");
        }
        order.setStatus(PayStatus.FINISH.getStatus());
        if (orderMapper.updateById(order) <= 0) {
            throw new RuntimeException();
        }
    }

    @Override
    public List<OrderAdminListVo> listByStatus(Integer orderStatus, Integer refundStatus) {
        return orderMapper.listByStatus(orderStatus, refundStatus);
    }

    @Override
    public void timeOutOrderCheck() {
        List<Order> status = orderMapper.selectList(new QueryWrapper<Order>().eq("status", PayStatus.WAITING.getStatus()));
        status.forEach(order -> {
            // 假设2分钟后不支付为超时
            if (LocalDateTime.now().minusMinutes(2).compareTo(order.getCreateTime()) >= 0) {
                // 恢复库存
                List<OrderDetail> orderDetailList = orderDetailMapper.selectList(new QueryWrapper<OrderDetail>().eq("order_sn", order.getOrderSn()));
                orderDetailList.forEach(orderDetail -> gameGoodsApplicationService.stock(orderDetail.getGameGoodsId(), -orderDetail.getNum()));
                order.setStatus(PayStatus.CANCEL.getStatus());
                if (orderMapper.updateById(order) <= 0) {
                    throw new RuntimeException();
                }
                // 加入日志
                orderLogService.add(new OrderLogVo().setOrderSn(order.getOrderSn())
                        .setUserId(order.getUserId())
                        .setMoney(new BigDecimal(0))
                        .setMessage("订单编号["+ order.getOrderSn() +"]订单已超时未支付，系统自动取消该订单"));
            }
        });
    }

}
